package j2metris.util;

/**
 * Represents a <code>Runnable</code> whose <code>run()</code> method can be
 * implemented in a tight loop. This replaces the deprecated <code>Thread.stop()</code>
 * method, and is designed to ensure more prompt cessation of execution than
 * <code>Thread.interrupt()</code> can guarantee.
 */
public abstract class StoppableRunnable implements Runnable
{
    private boolean shouldContinue = true;

    /**
     * Initial set-up performed before the loop begins.
     */
    public abstract void start();

    /**
     * An additional check that the subclass can implement to determine whether this
     * object should cease execution.
     *
     * @return <code>true</code> if the object should continue running; <code>false</code>
     * otherwise.
     */
    public abstract boolean shouldContinue();

    /**
     * The main loop of execution; analagous to <code>Runnable.run()</code>,
     * except that it will loop until the object is stopped or
     * <code>shouldContinue()</code> returns <code>false</code>.
     */
    public abstract void loop() throws Exception;

    /**
     * Clean-up performed just once, after the loop finishes.
     */
    public abstract void finish();

    /**
     * Performs <code>start()</code>. Then, while the object has not been stopped
     * and the derived <code>shouldContinue()</code> method returns <code>true</code>,
     * performs <code>loop()</code>. Then performs <code>finish()</code>.
     */
    public void run()
    {
        start();
        try
        {
            while(shouldContinue && shouldContinue())
                loop();
        }
        catch(Exception e)
        {
            handle(e);
        }
        finish();
    }

    /**
     * If the loop throws an exception, it will be delegated to this method.
     */
    public abstract void handle(Exception e);

    /**
     * Schedules this object for cessation of execution. This method does not
     * guarantee that the object will have stopped by the time it returns;
     * use <code>Thread.join()</code> if that is necessary.
     */
    public void stop()
    {
        shouldContinue = false;
    }
}
